Open In Colab

banner_AML.jpg

  • Integrante 1: Lina María Gómez Mesa
  • Integrante 2: María Catalina Ibáñez Piñeres

Contexto y objetivos.¶

Generación de paleta de colores a partir de imágenes con técnicas de machine learning no supervisado¶

Una paleta de colores es un conjunto de tonos que se utilizan juntos para crear un efecto armonioso, coherente y atractivo en las representaciones visuales (diseño gráfico, cine, fotografía, pintura, etc.), así como para transmitir mensajes y generar emociones determinados, de acuerdo con la intencionalidad del autor de la obra.

En un contexto de amplia demanda de herramientas que puedan asistir a diseñadores gráficos, directores de arte, pintores y creadores de contenido, entre otros, para la selección rápida y adecuada de los colores apropiados para sus obras, una aplicación para configurar paletas de colores a partir de imágenes sería de mucha utilidad.

Una vía para lograr una herramienta como esta es utilizar técnicas de machine learning no supervisado sobre imágenes para visualizar la distribución de los colores presentes en estas y generar, de manera automática, modelos de paletas de colores. En esta primera aproximación el método va a permitir identificar los colores en una imagen para construir un muestrario por similitud de píxeles, lo cual puede ser muy útil para estudios de marketing, psicología, medicina, arte, ambiente, entre otros. Por ejemplo, se podrían extraer los colores de las diferentes superficies de la Tierra en una imagen satelital para estudiar la distribución de la vegetación o de la contaminación.

Los datos están asociados con imágenes de obras de arte. Pueden ser descargados a partir de este enlace.

Actividades a realizar¶

  1. Recopilación de las imágenes a partir del repositorio. La idea es seleccionar un conjunto diverso de muestras en diferentes estilos artísticos (no más de 10).

  2. Preparación de las imágenes para el entrenamiento y prueba del modelo. Para este paso construir un pipeline que integre las transformaciones que se consideren adecuadas.

  3. Desarrollo del modelo de agrupación para identificar los colores presentes en las imágenes.

  4. Creación de un modelo que transforme los grupos de colores identificados en un muestrario representativo. Adicionalmente, se debe mostrar la distribución de los colores de la imagen en un espacio de dos dimensiones utilizando t-SNE.

NOTA: La calificación será sobre notebook ejecutado.

Consideraciones:¶

  • El algoritmo de agrupación a utilizar queda a consideración de cada grupo, pero es importante justificar la elección.

  • Se debe evidenciar el desempeño del método construido mostrando la paleta para al menos cuatro (4) imágenes de diferentes estilos, con la visualización de la distribución de colores en el espacio de dos dimensiones.

  • Un diagrama general del método que se quiere desarrollar se muestra en la siguiente figura:

Este código en su mayoría está basado en: "https://www.kaggle.com/code/juandaviddev/color-palette/notebook"

0. Importar librerías¶

In [1]:
import pandas as pd
import numpy as np
import os
import os.path as osp
import pandas as pd
import requests
from sklearn.preprocessing import StandardScaler, RobustScaler
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans, DBSCAN, AgglomerativeClustering
from sklearn.decomposition import PCA, IncrementalPCA
from sklearn.metrics import silhouette_score, silhouette_samples, rand_score
from scipy.cluster.hierarchy import dendrogram, linkage

import matplotlib.pyplot as plt
import matplotlib.cm as cm
import seaborn as sns
import os
import pandas as pd

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors

import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import AgglomerativeClustering
from sklearn.metrics import silhouette_score

pd.set_option('display.max_colwidth', None)

Punto 1: Recopilación de Imágenes¶

In [2]:
img_classes = pd.read_csv("Data/classes.csv")

sample_10 = pd.read_csv("Data/sample_10.csv", header=None)
lista = sample_10[0].unique()
img_selected = []
diccio = {}
for img in range(len(lista)):
    url =lista[img].split("4202543/")[1].split("?X-Goog-Algorithm")[0]
    img_selected.append(url)
    diccio[url] = lista[img][1:-1]
img_selected
Out[2]:
['Contemporary_Realism/lucian-freud_factory-in-north-london.jpg',
 'Early_Renaissance/filippo-lippi_disputation-in-the-synagogue-detail-1465.jpg',
 'Impressionism/armand-guillaumin_moulins-en-hollandee-1904.jpg',
 'Cubism/albert-gleizes_untitled-3.jpg',
 'Naive_Art_Primitivism/andre-bauchant_le-bouquet-1928.jpg',
 'Northern_Renaissance/albrecht-altdorfer_the-battle-of-issus-1529.jpg',
 'Pop_Art/aldo-mondino_collage-1973.jpg',
 'Symbolism/a.y.-jackson_smart-river-alaska-1945.jpg',
 'Fauvism/andre-derain_figures-from-a-carnival.jpg',
 'Art_Nouveau_Modern/aladar-korosfoi-kriesch_lady-with-tiara.jpg']
In [3]:
filtered_img_classes = img_classes[img_classes['filename'].isin(img_selected)]
filtered_img_classes
Out[3]:
filename artist genre description phash width height genre_count subset
2262 Art_Nouveau_Modern/aladar-korosfoi-kriesch_lady-with-tiara.jpg aladar korosfoi kriesch ['Art Nouveau Modern'] lady-with-tiara cc2bb3d64c799039 1382 1740 1 train
10485 Contemporary_Realism/lucian-freud_factory-in-north-london.jpg lucian freud ['Contemporary Realism'] factory-in-north-london ddc75638863a2ac6 1394 1382 1 train
10622 Cubism/albert-gleizes_untitled-3.jpg albert gleizes ['Cubism'] untitled-3 cfb63198ce649893 1936 1382 1 train
12821 Early_Renaissance/filippo-lippi_disputation-in-the-synagogue-detail-1465.jpg filippo lippi ['Early Renaissance'] disputation-in-the-synagogue-detail-1465 81367edb17564c4a 1382 1921 1 train
18528 Fauvism/andre-derain_figures-from-a-carnival.jpg andre derain ['Fauvism'] figures-from-a-carnival b08bcd2083f2decd 1897 1382 1 train
21099 Impressionism/armand-guillaumin_moulins-en-hollandee-1904.jpg armand guillaumin ['Impressionism'] moulins-en-hollandee-1904 9ef2e00149ff0f31 1718 1382 1 train
32815 Naive_Art_Primitivism/andre-bauchant_le-bouquet-1928.jpg andre bauchant ['Naive Art Primitivism'] le-bouquet-1928 c296591b37643ccb 1382 1658 1 train
34999 Northern_Renaissance/albrecht-altdorfer_the-battle-of-issus-1529.jpg albrecht altdorfer ['Northern Renaissance'] the-battle-of-issus-1529 9d8cc47c2c8cea4f 1382 1784 1 train
59251 Symbolism/a.y.-jackson_smart-river-alaska-1945.jpg a.y. jackson ['Symbolism', 'Art Nouveau Modern'] smart-river-alaska-1945 d23fa9a0d78f0d28 1877 1382 2 train
73379 Pop_Art/aldo-mondino_collage-1973.jpg aldo mondino ['Pop Art'] collage-1973 ba23c43f93c4f8c2 1382 1742 1 test
In [4]:
filtered_img_classes.loc[:, 'url'] = filtered_img_classes['filename'].map(diccio)
/var/folders/r5/cc3y743j5ys_g9v6b67d72jh0000gn/T/ipykernel_25150/4201899911.py:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  filtered_img_classes.loc[:, 'url'] = filtered_img_classes['filename'].map(diccio)
In [10]:
def download_image(url, filename):
    response = requests.get(url)
    os.makedirs(os.path.dirname(filename), exist_ok=True)
    with open(filename, 'wb') as f:
        f.write(response.content)

for index, row in filtered_img_classes.iterrows():
    url = row['url']
    filename = row['filename']
    download_image(url, filename)
In [5]:
from PIL import Image

def load_image(filename):
    try:
        img = Image.open(filename)
        img = img.convert("RGB")
        return img
    except FileNotFoundError:
        return None

filtered_img_classes.loc[:, 'image'] = filtered_img_classes['filename'].apply(load_image)
/var/folders/r5/cc3y743j5ys_g9v6b67d72jh0000gn/T/ipykernel_25150/4036918011.py:11: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  filtered_img_classes.loc[:, 'image'] = filtered_img_classes['filename'].apply(load_image)
In [6]:
import matplotlib.pyplot as plt

image = filtered_img_classes["image"].iloc[0]
plt.imshow(image)
plt.show()

Punto 2: Preparación de imágenes para la prueba del modelo¶

En el preprocesamiento de las diez imágenes, se realizaron los siguientes pasos:

  1. Re-escalar las imágenes por el factor de 0.5 tanto el width y height para que todas tengan el mismo tamaño de entrada para el algoritmo.
  2. Se realiza interpolación utilizando el método de interpolación INTER_AREA que considera los pixeles vecinos y sus colores para calcular el color de un pixel nuevo al redimensionar una imagen. Este método de interpolación mantiene la nitidez y la claridad de las imágenes a diferencia de otros.

  3. Una vez que se ha hecho el resize, se transforma la imagen a dataframe donde cada canal R,G,B se transforma en una columna distinta y cada fila es un pixel distinto. Esto se realizó con el fin de mantener las características de cada canal.

Por otro lado, al realizar el pipeline este tiene los siguientes pasos:

  1. Standard scaler: Normaliza los datos dado que Kmeans es un algoritmo basado en distancias y le puede impactar si las características de los datos tienen diferentes escalas.
  2. Clusterer: Implementa Kmeans para realizar la paleta de colores.
In [7]:
import pandas as pd
import numpy as np
import os
import cv2
import random
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import seaborn as sns

from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
from sklearn.cluster import KMeans, MeanShift, estimate_bandwidth
from sklearn.metrics import silhouette_score, silhouette_samples
from sklearn.cluster import DBSCAN
from sklearn.preprocessing import StandardScaler

class ImageReader:
    """Class to read and preprocess images.

    Attributes:
        - n_images (int): Number of images to read
        - file_type (str): File type of the images
        - directory (str): Directory where the images are stored

    Preprocessing includes:
    - Reading the images
    - Rescaling the images keeping the aspect ratio
    """

    def __init__(self, filtered_img: pd.DataFrame, scale: float = 0.1):
        self.images_names = []
        self.filter = filtered_img
        self.n_images = len(self.filter)
        self.original = self.read_images()
        self.images = self.read_images()
        self.images = self.rescale_images(self.images, scale)

    def read_images(self):
        """Read images from a directory and store them in a list"""
        images = []
        for filename in self.filter["filename"]:
            image = cv2.imread(filename)
            if image is not None:
                images.append(image)
                self.images_names.append(filename)
        return images

    def rescale_images(self, images: list, scale: float = 0.5):
        """Rescale images keeping the aspect ratio"""
        rescaled_images = []
        for image in images:
            width = int(image.shape[1] * scale)
            height = int(image.shape[0] * scale)
            dim = (width, height)
            rescaled_image = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)
            rescaled_images.append(rescaled_image)
        return rescaled_images

    def plot_images(self):
        """Plot the images"""
        n_cols = 2
        n_rows = int(np.ceil(self.n_images / n_cols))
        fig, axs = plt.subplots(n_rows, n_cols)
        for i, ax in enumerate(axs.flat):
            if i < self.n_images:
                ax.imshow(cv2.cvtColor(self.images[i], cv2.COLOR_BGR2RGB))
                ax.axis('off')
        plt.show()


class ImageDataProcessor:
    """Class to process images and extract features.

    Attributes:
        - image_reader: Instance of the ImageReader class.

    Methods:
        - extract_features: Extract features from the images
    """

    def __init__(self, image_reader: ImageReader):
        self.image_reader = image_reader
        if len(self.image_reader.images) > 1:
            self.image_reader.images = self.resize_images((100, 100))
        self.features = self.extract_features()

    def extract_features(self):
        """Create DataFrame with RGB values of the images"""
        features = []
        for image in self.image_reader.images:
            image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
            image = image.reshape((image.shape[0] * image.shape[1], 3))
            features.append(image)
        features = np.concatenate(features, axis=0)
        features = pd.DataFrame(features, columns=['r', 'g', 'b'])
        return features
    
    def resize_images(self, size: tuple):
        """Resize images to a given size"""
        resized_images = []
        for image in self.image_reader.images:
            resized_image = cv2.resize(image, size, interpolation=cv2.INTER_AREA)
            resized_images.append(resized_image)
        return resized_images
In [8]:
images = ImageReader(filtered_img=filtered_img_classes)
In [9]:
images.plot_images()

Punto 3: Desarrollo del modelo de agrupación para identificar los colores presentes en las imágenes¶

In [10]:
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.cluster import KMeans, MeanShift, estimate_bandwidth, DBSCAN, AgglomerativeClustering, SpectralClustering, MeanShift
from sklearn.metrics import silhouette_score, silhouette_samples

class ImageClustering:
    """Class to cluster images using different clustering algorithms.

    Attributes:
        - image_data_processor: Instance of the ImageDataProcessor class.
        - clusterer: Clustering algorithm to use.
        - kwargs: Additional parameters for the clustering algorithm.

    Methods:
        - fit: Fit the clustering algorithm to the data.
        - plot_clusters: Plot the images and their respective clusters.
    """
    
    def __init__(self, image_data_processor: ImageDataProcessor, clusterer, **kwargs):
        self.image_data_processor = image_data_processor
        self.clusterer = clusterer
        self.kwargs = kwargs
        self.pipeline = self.create_pipeline()

    def create_pipeline(self):
        """Create a pipeline for the clustering algorithm"""
        pipeline = Pipeline([
            ('scaler', StandardScaler()),
            ('clusterer', self.clusterer(**self.kwargs))
        ])
        return pipeline

    def fit(self):
        """Fit the clustering algorithm to the data"""
        self.pipeline.fit(self.image_data_processor.features)

    def predict_one(self, image):
        """Predict the cluster of a single image"""
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        image = image.reshape((image.shape[0] * image.shape[1], 3))
        return self.pipeline.named_steps['clusterer'].predict(image)

    def plot_clusters(self):
        """Plot the images and their respective clusters"""
        # get cluster labels
        cluster_labels = self.pipeline.named_steps['clusterer'].labels_
        n_clusters = len(np.unique(cluster_labels))
        centroids = self.pipeline.named_steps['clusterer'].cluster_centers_
        rgb_values = self.pipeline.named_steps['scaler'].inverse_transform(centroids)
        rgb_values = rgb_values / 255
        
        def _add_infig_color_palette(fig, rgb_values, n_clusters):
            # add color palette to the figure
            ax = fig.add_axes([0.1, 0.9, 0.1, 0.1])
            ax.imshow([rgb_values], aspect='auto')
            ax.axis('off')
            ax.set_title('Color palette')
            return fig
        
        if len(self.image_data_processor.image_reader.images) == 1:
            fig, ax = plt.subplots(1, 1)
            ax.imshow(cv2.cvtColor(self.image_data_processor.image_reader.original[0], cv2.COLOR_BGR2RGB))
            ax.axis('off')
        else:
            n_cols = 3
            n_rows = int(np.ceil(len(self.image_data_processor.image_reader.original) / n_cols))
            fig, axs = plt.subplots(n_rows, n_cols)
            for i, ax in enumerate(axs.flat):
                if i < len(self.image_data_processor.image_reader.images):
                    ax.imshow(cv2.cvtColor(self.image_data_processor.image_reader.original[i], cv2.COLOR_BGR2RGB))
                    ax.axis('off')
        fig = _add_infig_color_palette(fig, rgb_values, n_clusters)
        plt.show()
In [11]:
class ClusteringEvaluator:
    """Class to evaluate performance of clustering algorithms.

    Attributes:
        - image_data_processor: Instance of the ImageDataProcessor class.
        - image_clustering: Instance of the ImageClustering class.

    Methods:
        - silhouette_score: Compute the silhouette score of the clustering algorithm.
        - silhouette_plot: Plot the silhouette plot of the clustering algorithm.
    """
    
    def __init__(self, image_data_processor: ImageDataProcessor, image_clustering: ImageClustering):
        self.image_data_processor = image_data_processor
        self.image_clustering = image_clustering

    def silhouette_score(self):
        """Compute the silhouette score of the clustering algorithm"""
        cluster_labels = self.image_clustering.pipeline.named_steps['clusterer'].labels_
        score = silhouette_score(self.image_data_processor.features, cluster_labels)
        return score

    def silhouette_plot(self):
        """Plot the silhouette plot of the clustering algorithm"""
        cluster_labels = self.image_clustering.pipeline.named_steps['clusterer'].labels_
        silhouette_values = silhouette_samples(self.image_data_processor.features, cluster_labels)
        y_lower = 10
        fig, ax = plt.subplots(1, 1, figsize=(8, 8))
        for i in range(len(np.unique(cluster_labels))):
            cluster_silhouette_values = silhouette_values[cluster_labels == i]
            cluster_silhouette_values.sort()
            size_cluster_i = cluster_silhouette_values.shape[0]
            y_upper = y_lower + size_cluster_i
            color = cm.nipy_spectral(float(i) / len(np.unique(cluster_labels)))
            ax.fill_betweenx(np.arange(y_lower, y_upper), 0, cluster_silhouette_values, facecolor=color, edgecolor=color, alpha=0.7)
            ax.text(-0.05, y_lower + 0.5 * size_cluster_i, str(i))
            y_lower = y_upper + 10

        ax.set_title('Silhouette plot')
        ax.set_xlabel('Silhouette values')
        ax.set_ylabel('Cluster label')
        ax.axvline(x= self.silhouette_score(), color='red', linestyle='--')
        ax.set_yticks([])
        plt.show()
 
In [21]:
class DimReducer:
    """Class to reduce dimensions usin t-sne and pca
    
    Attributes:
        - image_processor: ImageProcessor instance
        - image_clustering: ImageClustering instance
    
    Methods:
        - pca_reduction: reduce dims using pca
        - tsne_reduction: reduce dims using t-sne
    """
    def __init__(self, image_processor: ImageDataProcessor, image_clustering: ImageClustering) -> None:
        self.image_processor = image_processor
        self.image_clustering = image_clustering
        
    def get_tsne(self, n_components: int):
        """Run t-sne"""
        tsne = TSNE(n_components=n_components)
        return tsne.fit_transform(self.image_processor.features)

    
    def plot_tsne_with_cluster_colors(self, n_components: int):
        tsne = TSNE(n_components=n_components)
        reduced_features = tsne.fit_transform(self.image_processor.features)

        cluster_labels = self.image_clustering.pipeline.named_steps['clusterer'].labels_
        n_clusters = len(np.unique(cluster_labels))
        
        centroids = self.image_clustering.pipeline.named_steps['clusterer'].cluster_centers_
        rgb_values = self.image_clustering.pipeline.named_steps['scaler'].inverse_transform(centroids) / 255

        fig, ax = plt.subplots(1, 1, figsize=(5, 5))
        for i in range(n_clusters):
            cluster_indices = np.where(cluster_labels == i)[0]
            ax.scatter(reduced_features[cluster_indices, 0], reduced_features[cluster_indices, 1], 
                    c=[rgb_values[i]], label=f'Cluster {i}')
        
        ax.set_xlabel('First component')
        ax.set_ylabel('Second component')
        ax.set_title('t-SNE with Cluster Colors')
        ax.legend()
        plt.show()

K-MEANS¶

K-means es un algoritmo de clusterización, que tiene como objetivo dividir n observaciones en k clusters en los que cada observación pertenece al cluster con la media más cercana (centros de cluster o centroide de cluster), sirviendo como prototipo del grupo. En este método no supervisado, el número k es un hiperparámetro del algoritmo. Para saber el k-óptimo se utiliza el método de la silueta. Este método calcula el coeficiente de la silueta para evaluar la calidad del agrupamiento obtenido. Un valor más alto de este índice indica un caso más deseable del número de clústers. Este se calcula de forma: $s(i) = \frac{b-a}{max(a,b)}$ donde a es el promedio de la distancia de la observación i con las demás observaciones del mismo clúster y b es la distancia mínima a otro clúster.

Por lo tanto, se utiliza el coeficiente de la silueta para determinar el número de clústeres que se deben utilizar en general en las diez imágenes seleccionadas. Además, se decidió utilizar Kmeans sobre otros algorítmos de clusterización porque K-means es un algoritmo de clustering ampliamente utilizado que es simple de implementar, eficiente computacionalmente y es efectivo para encontrar agrupamientos.

Búsqueda de hiperparámetros¶

En primer lugar, se varía el hiperparámetro k dado que representa determina la cantidad de grupos distintos que se identificarán en el conjunto de datos. En este caso, k representa el número de colores que se eligirán para la paleta de cada imagen. Por otro lado, se eligió variar el hiperparámetro init dado que controla la forma en que se inicializan los centroides. Esta puede ser aleatoria (los centroides se inicializan aleatoriamente) y K-means++ (selecciona iterativamente los centroides de una manera que maximiza la distancia entre ellos). Este hiperparámetro conduce a agrupaciones muy diferentes de los mismos datos por lo que puede llegar a variar el coeficiente de silueta.

Luego de realizar el análisis de los hiperparámetros y variar el número de clústers se obtuvo que el mejor hiperparámetro fue con un número k=5 y init = k-means++, donde el coeficiente de silueta obtuvo un resultado de 0.41059. Por otro lado, no se observó una diferencia significativa entre el hiperparámetro _init k-means++ y random dado que la variación de los resultados es muy baja.

In [12]:
# Lista de hiperparámetros
n_clusters = [5,6,7]
init = ['k-means++', 'random']
image_data_processor = ImageDataProcessor(images)
In [13]:
for i in init:
    for n_cluster in n_clusters:
        image_clustering = ImageClustering(image_data_processor, KMeans, n_clusters=n_cluster, init = i)
        image_clustering.fit()
        clustering_evaluator = ClusteringEvaluator(image_data_processor, image_clustering)
        print(f'KMeans with {n_cluster} clusters and {i} init: {clustering_evaluator.silhouette_score()}')
        clustering_evaluator.silhouette_plot()
KMeans with 5 clusters and k-means++ init: 0.4105965018092948
KMeans with 6 clusters and k-means++ init: 0.3828795773708798
KMeans with 7 clusters and k-means++ init: 0.37425368335169396
KMeans with 5 clusters and random init: 0.41027815142806007
KMeans with 6 clusters and random init: 0.3951178528657418
KMeans with 7 clusters and random init: 0.37417940614720036

Punto 4: Creación de un modelo que transforme los grupos de colores identificados en un muestrario representativo. Adicionalmente, mostrar la distribución de los colores de la imagen en un espacio de dos dimensiones utilizando t-SNE.¶

Dado que el número de imágenes es bajo (10) se decidió utilizar t-SNE para visualizar los resultados de los clústeres obtenidos en vez de reducir la dimensionalidad antes de aplicar K-Means. t-SNE transforma los datos en un espacio de dimensión reducida que puede visualizarse fácilmente en un plano de dos dimensiones. Utilizar t-SNE al final permite visualizar los resultados del clustering de K-means de una manera intuitiva e interpretable, lo que facilita la identificación de las paletas de colores dominantes en la imagen. Finalmente, usar t-SNE al final permite preservar las relaciones de color entre los pixeles cercanos, lo que resulta en paletas de color más representativas de la imagen original.

Para n_clusters = 5

In [24]:
print(f"KMeans with 5 clusters")
for i in range(len(filtered_img_classes)):
    print("Imagen", i+1)
    images = ImageReader(filtered_img=filtered_img_classes.iloc[[i]])
    image_data_processor = ImageDataProcessor(images)
    image_clustering = ImageClustering(image_data_processor, KMeans, n_clusters=5, n_init="auto")
    image_clustering.fit()
    print("Paleta de colores")
    image_clustering.plot_clusters()
    dim_reducer = DimReducer(image_data_processor, image_clustering)
    print("t-SNE")
    dim_reducer.plot_tsne_with_cluster_colors(2)
KMeans with 5 clusters
Imagen 1
Paleta de colores
t-SNE
Imagen 2
Paleta de colores
t-SNE
Imagen 3
Paleta de colores
t-SNE
Imagen 4
Paleta de colores
t-SNE
Imagen 5
Paleta de colores
t-SNE
Imagen 6
Paleta de colores
t-SNE
Imagen 7
Paleta de colores
t-SNE
Imagen 8
Paleta de colores
t-SNE
Imagen 9
Paleta de colores
t-SNE
Imagen 10
Paleta de colores
t-SNE

Para n_clusters = 6

In [25]:
print(f"KMeans with 6 clusters")
for i in range(len(filtered_img_classes)):
    print("Imagen", i+1)
    images = ImageReader(filtered_img=filtered_img_classes.iloc[[i]])
    image_data_processor = ImageDataProcessor(images)
    image_clustering = ImageClustering(image_data_processor, KMeans, n_clusters=6, n_init="auto")
    image_clustering.fit()
    print("Paleta de colores")
    image_clustering.plot_clusters()
    dim_reducer = DimReducer(image_data_processor, image_clustering)
    print("t-SNE")
    dim_reducer.plot_tsne_with_cluster_colors(2)
KMeans with 6 clusters
Imagen 1
Paleta de colores
t-SNE
Imagen 2
Paleta de colores
t-SNE
Imagen 3
Paleta de colores
t-SNE
Imagen 4
Paleta de colores
t-SNE
Imagen 5
Paleta de colores
t-SNE
Imagen 6
Paleta de colores
t-SNE
Imagen 7
Paleta de colores
t-SNE
Imagen 8
Paleta de colores
t-SNE
Imagen 9
Paleta de colores
t-SNE
Imagen 10
Paleta de colores
t-SNE

Para n_clusters = 7

In [26]:
print(f"KMeans with 7 clusters")
for i in range(len(filtered_img_classes)):
    print("Imagen", i+1)
    images = ImageReader(filtered_img=filtered_img_classes.iloc[[i]])
    image_data_processor = ImageDataProcessor(images)
    image_clustering = ImageClustering(image_data_processor, KMeans, n_clusters=7, n_init="auto")
    image_clustering.fit()
    print("Paleta de colores")
    image_clustering.plot_clusters()
    dim_reducer = DimReducer(image_data_processor, image_clustering)
    print("t-SNE")
    dim_reducer.plot_tsne_with_cluster_colors(2)
KMeans with 7 clusters
Imagen 1
Paleta de colores
t-SNE
Imagen 2
Paleta de colores
t-SNE
Imagen 3
Paleta de colores
t-SNE
Imagen 4
Paleta de colores
t-SNE
Imagen 5
Paleta de colores
t-SNE
Imagen 6
Paleta de colores
t-SNE
Imagen 7
Paleta de colores
t-SNE
Imagen 8
Paleta de colores
t-SNE
Imagen 9
Paleta de colores
t-SNE
Imagen 10
Paleta de colores
t-SNE

Conclusión¶

A pesar de que anteriormente se había determinado que el número de clústers óptimo era 5, se decidió aplicar el algoritmo con 6 y 7 clústers para observar si se obtenían resultados más claros y precisos. Sin embargo, se observó que el número de clústers óptimo, como lo indicaba el coeficiente de silueta, era 5, ya que con 6 y 7 clústers se observaron colores muy similares y se perdieron las diferencias entre los colores de la imagen original. Por lo tanto, se concluye que el número de clústers óptimo para las imágenes seleccionadas es 5.